#include "..\base\SampleBase.h"
#include "..\base\D3DUtil.h"
#include "..\base\Camera.h"
#include "..\base\Fps.h"
#include "Terrain.h"
#include <iostream>
#include <cstdlib>

class TerrainDriver : public SampleBase
{
private:
	ID3DXMesh*       m_ball;
	Camera           m_camera;
	Terrain*         m_terrain;
	FPSDisplayer*    m_fps;
	
public:
	virtual bool Setup()
	{
		m_fps = new FPSDisplayer(m_device);
		m_camera = Camera(Camera::LANDOBJECT);
		//m_camera.SetPosition(&D3DXVECTOR3(0.0f, 10.0f, -15.0f));

		D3DXVECTOR3  lightDirection(0.0f, 1.0f, 0.0f);
		m_terrain  = new Terrain(m_device, "coastMountain64.raw", 64, 64, 4, 0.5f);
		m_terrain->GenerateTexture(&lightDirection);

		m_device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
		m_device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
		m_device->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR);
		
		// Setup a directional light.
		D3DXVECTOR3 dir(1.0f, -0.0f, 0.25f);
		D3DXCOLOR   c = d3dutil::WHITE;
		D3DLIGHT9	dirLight = d3dutil::InitDirectionalLight(&dir, &c);

		// Set and Enable the light
		m_device->SetLight(0, &dirLight);
		m_device->LightEnable(0, true);
		
		D3DXCreateSphere(
			m_device,
			0.5f, // radius
			10,   // slices
			10,   // stacks
			&m_ball,
			0);

		// Set projection matrix
		D3DXMATRIX proj;
		D3DXMatrixPerspectiveFovLH(
			&proj, 
			D3DX_PI / 4.0f,
			(float)m_windowWidth / (float)m_windowHeight,
			1.0f,
			1000.0f);
		m_device->SetTransform(D3DTS_PROJECTION, &proj);

		return true;
	}


	virtual void Cleanup()
	{
		d3dutil::Delete<Terrain*>(m_terrain);
		d3dutil::Release<ID3DXMesh*>(m_ball);
		d3dutil::Delete<FPSDisplayer*>(m_fps);
	}

	virtual bool Display(float timeDelta)
	{
		static float currentHeight = 0.0f;
		if (m_device)
		{
			m_camera.ControllMe(timeDelta);
			D3DXVECTOR3  camera_pos;
			m_camera.GetPosition(&camera_pos);
			float height = m_terrain->GetHeight(camera_pos.x, camera_pos.z);

			/*if (::abs(height - currentHeight) > 1.0f)
			{
				m_terrain->GetHeightVerbose(pos.x, pos.z);
				std::cout<<"Current Position: "<<pos.x<<", " <<pos.y<<", " <<height<<std::endl;
				currentHeight  = height;
			}*/

			camera_pos.y = height; // add height because we're standing up
			//m_camera.SetPosition(&camera_pos);

			D3DXVECTOR3 look;
			m_camera.GetLook(&look);
			look = -look;
			D3DXVec3Normalize(&look, &look);
			D3DXVec3Scale(&look, &look, 10.0f);
			look.y += 40.0f;
			D3DXVec3Add(&look, &camera_pos, &look);
			D3DXMATRIX V;
			m_camera.GetViewMatrix(&V, &look);
			m_device->SetTransform(D3DTS_VIEW, &V);

			m_device->Clear(0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0xffffffff, 1.0f, 0);
			m_device->BeginScene();

			D3DXMATRIX I;
			D3DXMatrixIdentity(&I);

			if(m_terrain)
				m_terrain->Draw(&I, false);
			
			DrawBall(camera_pos.x, camera_pos.y, camera_pos.z);

			m_fps->DrawFPSText(timeDelta);
			
			m_device->EndScene();
			m_device->Present(0, 0, 0, 0);
		}
		return true;
	}

	void DrawBall(float x, float y, float z)
	{		
		// Turn on lighting
		m_device->SetRenderState(D3DRS_LIGHTING, true);
		// Turn on secular lighting and instruct Direct3D
		// to renormailize the normals.
		m_device->SetRenderState(D3DRS_NORMALIZENORMALS, true);
		m_device->SetRenderState(D3DRS_SPECULARENABLE, true);

		D3DXMATRIX W;
		/*D3DXVECTOR3 look;
		D3DXVECTOR3  pos;
		m_camera.GetPosition(&pos);
		m_camera.GetLook(&look);

		D3DXVec3Normalize(&look, &look);
		D3DXVec3Scale(&look, &look, 10.0f);
		D3DXVec3Add(&look, &pos, &look);*/
		D3DXMatrixTranslation(&W, x, y, z);

		m_device->SetTransform(D3DTS_WORLD, &W);
		m_device->SetTexture(0, 0);
		m_device->SetMaterial(&d3dutil::RED_MTRL);
		m_ball->DrawSubset(0);
		//m_device->SetMaterial(0);
		
		// Turn off lighting
		m_device->SetRenderState(D3DRS_LIGHTING, false);
		// Turn off secular lighting and instruct Direct3D
		// to re-normailize the normals.
		m_device->SetRenderState(D3DRS_NORMALIZENORMALS, false);
		m_device->SetRenderState(D3DRS_SPECULARENABLE, false);
	}
};

SampleBase* g_CreateSample()
{
	return new TerrainDriver;
}
